//Copyright (c) 2009, Sandeep Datta
//All rights reserved.
//
//Redistribution and use in source and binary forms, with or without modification, are permitted provided 
//that the following conditions are met:
//
//* Redistributions of source code must retain the above copyright notice, this list of conditions and 
//the following disclaimer.
//
//* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 
//the following disclaimer in the documentation and/or other materials provided with the distribution.
//
//* Neither the name of Sandeep Datta nor the names of its contributors may be used to endorse or 
//promote products derived from this software without specific prior written permission.
//
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 
//IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
//FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
//CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
//CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
//WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
//OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


using System;
using System.Collections.Generic;
using System.Text;
using WindowsInstaller;
using System.IO;
using System.Runtime.InteropServices;

namespace SharpInstall
{
    public class Msi
    {
        private MSIWrapperClass _msi = new MSIWrapperClass();
        private string _msiPath;
        private MSIWrapperClass _msiWrapper = new MSIWrapperClass();
        private Database _db;

        public Msi(string path, FileMode mode)
        {

            if (    (mode & FileMode.Append) == FileMode.Append 
                ||  (mode & FileMode.Truncate) == FileMode.Truncate )
                throw new ArgumentException("Invalid file open mode", "mode");

            bool exisits = File.Exists(path);
            bool create = false;
            bool deleteOld = false;

            switch (mode)
            {
                case FileMode.Create:
                case FileMode.OpenOrCreate:
                    create = !exisits;
                    break;
                case FileMode.CreateNew:
                    create = true;
                    deleteOld = true;
                    break;
                case FileMode.Open:
                    create = false;
                    deleteOld = false;
                    break;
            }

            _msiPath = path;

            if (deleteOld)
                File.Delete(_msiPath);

            if (create)
                createMsi(_msiPath);

            //Open the MSI database for future transactions
            _db = _msiWrapper.OpenDatabase(_msiPath, MsiOpenDatabaseMode.msiOpenDatabaseModeTransact);
           
        }

        private void createMsi(string path)
        {
            Database x = _msiWrapper.OpenDatabase(_msiPath, MsiOpenDatabaseMode.msiOpenDatabaseModeCreate);
            x.Commit();
            Marshal.ReleaseComObject(x);
        }

        public void AddTable(TableInfo ti)
        {
            AddTable(ti.Name, ti.Column);
        }

        public void AddTable(string tableName, ColumnInfo[] columnInfo)
        {
            //CREATE TABLE `table name` (`col1` CHAR(255) NOT NULL, `col2` LONG PRIMARY KEY `col1`, `col2` )

            StringBuilder query = new StringBuilder();
            
            query.AppendFormat("CREATE TABLE `{0}` ( ", tableName);

            int i = 0;
            for (; i < columnInfo.Length - 1; i++ )
            {
                query.AppendFormat("`{0}` {1}, "
                    , columnInfo[i].Name
                    , columnInfo[i].Type.GetFullSqlType());
            }

            query.AppendFormat("`{0}` {1} "
                    , columnInfo[i].Name
                    , columnInfo[i].Type.GetFullSqlType());

            //Primary key section
            query.Append("PRIMARY KEY ");
            
            int j = 0;

            if (j < columnInfo.Length && columnInfo[j].Type.IsPrimary)
                query.AppendFormat("`{0}`", columnInfo[j++].Name);

            for (; j < columnInfo.Length; j++)
            {
                if (columnInfo[j].Type.IsPrimary)
                    query.AppendFormat(", `{0}`", columnInfo[j].Name);
            }

            query.Append(")");
            string q = query.ToString();
            View v = _db.OpenView(q);
            v.Execute(null);
            Marshal.ReleaseComObject(v);
            _db.Commit();
        }
    }
}
